#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>

#include "AsyncBuffer.hpp"

namespace mylog
{
    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };
    using functor = std::function<void(Buffer &)>;
    class AsyncWorker
    {
    public:
        using ptr = std::shared_ptr<AsyncWorker>;
        AsyncWorker(const functor &cb, AsyncType async_type = AsyncType::ASYNC_SAFE)
            : async_type_(async_type),
              callback_(cb), // 回调函数，用来告诉工作器如何处理缓冲区里的数据（通常是 AsyncLogger::RealFlush）。
              stop_(false),
              thread_(std::thread(&AsyncWorker::ThreadEntry, this)) {} // thread_：创建后台线程，执行 ThreadEntry() 函数。注意：线程在构造函数里就启动。
        ~AsyncWorker() { Stop(); }
        void Push(const char *data, size_t len) // 写入日志
        {
            // 如果生产者队列不足以写下len长度数据，并且缓冲区是固定大小，那么阻塞
            std::unique_lock<std::mutex> lock(mtx_);
            if (AsyncType::ASYNC_SAFE == async_type_) // 控制生产者写入缓冲区；如果日志长度 len 必须 ≤ 生产者缓冲区剩余可写空间，生产者线程会阻塞，等待消费者线程刷盘释放空间
                cond_productor_.wait(lock, [&]()
                                     { return len <= buffer_productor_.WriteableSize(); });
            buffer_productor_.Push(data, len);
            cond_consumer_.notify_one();
        }
        void Stop()
        {
            stop_ = true; // 设置 stop_ = true → 后台线程退出循环
            cond_consumer_.notify_all(); // 所有线程把缓冲区内数据处理完就结束了
            thread_.join();
        }

    private:
        void ThreadEntry()
        {
            while (!stop_) // stop_ 为 true 或者生产者缓冲区不为空
            {
                { // 缓冲区交换完就解锁，让productor继续写入数据
                    std::unique_lock<std::mutex> lock(mtx_);
                    cond_consumer_.wait(lock, [&]()
                                        { return stop_ || !buffer_productor_.IsEmpty(); });
                    buffer_productor_.Swap(buffer_consumer_);
                    // 固定容量的缓冲区才需要唤醒
                    if (async_type_ == AsyncType::ASYNC_SAFE) // 安全模式下，生产者可能因为缓冲区写满而阻塞；消费者线程刷走数据后，通知生产者线程可以继续写
                        cond_productor_.notify_one();
                }
                callback_(buffer_consumer_); // 调用回调函数对缓冲区中数据进行处理，调用 AsyncLogger::RealFlush()，把消费者缓冲区的数据写到文件 / 控制台 / 网络等；注意，这里是在后台线程中执行的 真正刷盘操作
                buffer_consumer_.Reset();
                if (stop_ && buffer_productor_.IsEmpty())
                    return;
            }
        }

    private:
        AsyncType async_type_; // 异步类型，安全/不安全
        std::atomic<bool> stop_; // 用于控制异步工作器的启动/停止
        std::mutex mtx_; // 保护缓冲区和条件变量的访问
        mylog::Buffer buffer_productor_; // 生产者缓冲区，供 Push 写入日志
        mylog::Buffer buffer_consumer_; // 消费者缓冲区，供后台线程刷盘
        std::condition_variable cond_productor_; // 安全模式下用于生产者等待缓冲区空间
        std::condition_variable cond_consumer_; // 消费者线程等待新日志
        std::thread thread_; // 后台线程执行 ThreadEntry

        functor callback_; // 回调函数，用来告知工作器如何落地； 定义如何处理消费者缓冲区的数据
    };
} // namespace mylog